﻿#region Copyrights Notice
//©2010 Microsoft Corporation. All rights reserved.
#endregion

#region usings
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Deployment.WindowsInstaller;
using System.DirectoryServices;
using System.Runtime.InteropServices;
using Microsoft.Web.Administration;
#endregion

namespace SetupCustomActionsLibrary
{
    public class IisCA
    {
        [DllImport("Netapi32.dll")]
        static extern int NetApiBufferFree(IntPtr Buffer);

        [DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        static extern int NetGetJoinInformation(string server, out IntPtr domain, out NetJoinStatus status);

        // Win32 Result Code Constant
        const int ErrorSuccess = 0;

        // NetGetJoinInformation() Enumeration
        public enum NetJoinStatus
        {
            NetSetupUnknownStatus = 0,
            NetSetupUnjoined,
            NetSetupWorkgroupName,
            NetSetupDomainName
        } // NETSETUP_JOIN_STATUS
        /// <summary>
        ///  This function populates the combo box with lsit of websites
        /// </summary>
        /// <param name="xiSession"></param>
        /// <returns></returns>
        [CustomAction]
        public static ActionResult FillPortalWebsiteNameList(Session xiSession)
        {
            View lView = xiSession.Database.OpenView("DELETE FROM ComboBox WHERE ComboBox.Property='WCFWEBSITE'");
            //clear the combo...just incase the user click Back and then Clicks Next
            lView.Execute(); 

            lView = xiSession.Database.OpenView("SELECT * FROM ComboBox");
            lView.Execute();

            DirectoryEntry lIis = new DirectoryEntry("IIS://localhost/w3svc");

            int lIndex = 1;
            string lWebsiteName = string.Empty; 
            string firstEntry = string.Empty;  
            foreach (DirectoryEntry lEntry in lIis.Children)
            {
                if (lEntry.SchemaClassName == "IIsWebServer")
                {
                    xiSession.Log("Found web server entry: " + lEntry.Name);

                    lWebsiteName = (string)lEntry.Properties["ServerComment"].Value;
                    xiSession.Log("Website name: " + lWebsiteName);

                    xiSession.Log("Creating record");
                    Record lRecord = xiSession.Database.CreateRecord(4);

                    xiSession.Log("Setting record details");
                    lRecord.SetString(1, "WCFWEBSITE");
                    lRecord.SetInteger(2, lIndex);
                    lRecord.SetString(3, lWebsiteName); // Use lWebsiteName only if you want to look up the site by name. 
                    lRecord.SetString(4, lWebsiteName);
                    
                    xiSession.Log("Adding record");
                    lView.Modify(ViewModifyMode.InsertTemporary, lRecord);

                    //store the first entry and populate the combo with it
                    if(lIndex == 1)
                        firstEntry = lWebsiteName; 
                    ++lIndex;
                }
            }
            //select the first entry in the combo
            xiSession["WCFWEBSITE"] = firstEntry;
            lView.Close();
            return ActionResult.Success;
        }
        /// <summary>
        /// This function populates the combo box with lsit of websites
        /// </summary>
        /// <param name="xiSession"></param>
        /// <returns></returns>
        [CustomAction]
        public static ActionResult FillWebsiteNameList(Session xiSession)
        {
            View lView = xiSession.Database.OpenView("DELETE FROM ComboBox WHERE ComboBox.Property='WEBSITE'");
            //clear the combo...just incase the user click Back and then Clicks Next
            lView.Execute(); 

            lView = xiSession.Database.OpenView("SELECT * FROM ComboBox");
            lView.Execute();

            DirectoryEntry lIis = new DirectoryEntry("IIS://localhost/w3svc");

            int lIndex = 1;
            string lWebsiteName = string.Empty;
            string firstEntry = string.Empty;  
            foreach (DirectoryEntry lEntry in lIis.Children)
            {
                if (lEntry.SchemaClassName == "IIsWebServer")
                {
                    xiSession.Log("Found web server entry: " + lEntry.Name);

                    lWebsiteName = (string)lEntry.Properties["ServerComment"].Value;
                    xiSession.Log("Website name: " + lWebsiteName);

                    xiSession.Log("Creating record");
                    Record lRecord = xiSession.Database.CreateRecord(4);

                    xiSession.Log("Setting record details");
                    lRecord.SetString(1, "WEBSITE");
                    lRecord.SetInteger(2, lIndex);
                    lRecord.SetString(3, lWebsiteName); // Use lWebsiteName only if you want to look up the site by name. 
                    lRecord.SetString(4, lWebsiteName);

                    xiSession.Log("Adding record");
                    lView.Modify(ViewModifyMode.InsertTemporary, lRecord);

                    //store the first entry and populate the combo with it
                    if (lIndex == 1)
                        firstEntry = lWebsiteName; 

                    ++lIndex;
                }
            }
            //select the first entry in the combo
            xiSession["WEBSITE"] = firstEntry;
            lView.Close();
            return ActionResult.Success;
        }
        
        /// <summary>
        /// Returns the domain name to which computer is joined to, or "" if not joined. This function is requred to set
        /// the appropriate permission on the Portal database
        /// </summary>
        /// <param name="xiSession"></param>
        /// <returns></returns>
        [CustomAction]             
        public static ActionResult GetJoinedDomain(Session xiSession)
        {
            int result = 0;
            string domain = null;
            IntPtr pDomain = IntPtr.Zero;
            NetJoinStatus status = NetJoinStatus.NetSetupUnknownStatus;
            try
            {
                result = NetGetJoinInformation(null, out pDomain, out status);
                if (result == ErrorSuccess &&
                    status == NetJoinStatus.NetSetupDomainName)
                {
                    domain = Marshal.PtrToStringAuto(pDomain);
                }
            }
            finally
            {
                if (pDomain != IntPtr.Zero) NetApiBufferFree(pDomain);
            }
            if (domain == null) domain = "";

            xiSession["DOMAIN"] = domain;
            //set the computer name as well
            xiSession["COMPUTERNAME"] = Environment.MachineName; 
            return ActionResult.Success;
        }
        /// <summary>
        /// This function return the root path of the Websites for PortalService and PortalWEbsite depending on whether
        /// these featues are selected for installation
        /// </summary>
        /// <param name="xiSession"></param>
        /// <returns></returns>
        [CustomAction]
        public static ActionResult UpdateWebSitePath(Session xiSession)
        {
            //get the features that were installed
            string featuresInstalled = xiSession["ADDLOCAL"];
            //check if Portal WebSite is installed
            if (featuresInstalled.Contains("PortalWeb") == true)
            {
                string website = xiSession["WEBSITE"];
                string vdName = xiSession["VDNAME"];
                xiSession["WEBINSTALLDIR"] = GetWebsitePath(website, vdName);
            }

            //check if Portal SErvice is installed
            if (featuresInstalled.Contains("PortalSvc") == true)
            {
                string website = xiSession["WCFWEBSITE"];
                string vdName = xiSession["WCFVDNAME"];
                xiSession["WCFINSTALLDIR"] = GetWebsitePath(website, vdName);
            }

            return ActionResult.Success;
        }
        /// <summary>
        /// Returns WebSite path for a given WEbSite 
        /// </summary>
        /// <param name="xiSession"></param>
        /// <param name="website"></param>
        /// <param name="vdName"></param>
        private static string GetWebsitePath(string website, string vdName)
        {
            DirectoryEntry lIis = new DirectoryEntry("IIS://localhost/w3svc");
            int lIndex = 1;
            string webPath = string.Empty;  
            foreach (DirectoryEntry lEntry in lIis.Children)
            {
                if (lEntry.SchemaClassName == "IIsWebServer")
                {
                    int id = Convert.ToInt32(lEntry.Name);

                    DirectoryEntry site = new DirectoryEntry("IIS://localhost/W3SVC/" + id);
                    string siteName = site.Properties["ServerComment"].Value.ToString();

                    DirectoryEntry rootVDir = new DirectoryEntry("IIS://localhost/W3SVC/" + id + "/Root");
                    string rootPath = rootVDir.Properties["Path"].Value.ToString();

                    if (string.Compare(website, siteName, true) == 0)
                    {
                        if (vdName == "/")
                        {
                            //if "/" is entered as root path just return the root path otehrwise suffix with the virtual
                            //directory name
                            webPath = rootPath;
                        }
                        else
                        {
                            webPath = rootPath + @"\" + vdName;
                        }
                    }
                    ++lIndex;
                }
            }
            return webPath;
        }
        
        /// <summary>
        /// This function changes the pipeline mode for the Portal Service and WebSite AppPools. In case of error, 
        /// the installer rollsback
        /// </summary>
        /// <param name="xiSession"></param>
        /// <returns></returns>
        [CustomAction]
        public static ActionResult ChangeAppPoolPipelineMode(Session xiSession)
        {            
            ServerManager serverMgr = new ServerManager();
            //get the features that were installed
            string featuresInstalled = xiSession["ADDLOCAL"];

            ApplicationPool appPool = null;
            //check if Portal Service is installed
            if (featuresInstalled.Contains("PortalSvc") == true)
            {
                string appPoolName = xiSession["WCFAPPPOOL"];

                appPool = serverMgr.ApplicationPools[appPoolName];
                appPool.ManagedPipelineMode = ManagedPipelineMode.Integrated;
                serverMgr.CommitChanges();
                serverMgr.Dispose();  
            }

            //check if Portal WEb site is installed
            if (featuresInstalled.Contains("PortalWeb") == true)
            {
                string appWebPoolName = xiSession["APPPOOL"];
                appPool = serverMgr.ApplicationPools[appWebPoolName];
                appPool.ManagedPipelineMode = ManagedPipelineMode.Integrated;
                serverMgr.CommitChanges();
                serverMgr.Dispose();  
            }
            return ActionResult.Success;
        }

        /// <summary>
        /// This function gets called durign the uninstallation and just before the files are deleted from the drive
        /// This function looks up for the Applciation and deletes it. In case of error, the installer rollsback
        /// </summary>
        /// <param name="xiSession"></param>
        /// <returns></returns>
        [CustomAction]
        public static ActionResult DeleteVirtualDirectories(Session xiSession)
        {
            try
            {
                string webSite = xiSession["WCFWEBSITE"];
                //the path is relative to the root path of the website selected
                string applicationPath = "/" + xiSession["WCFVDNAME"];

                ServerManager mgr = new ServerManager();
                Site site = mgr.Sites[webSite];

                Application app = site.Applications[applicationPath];
                site.Applications.Remove(app);

                //if the WEb Site is not installed on the root site delete that application as well
                webSite = xiSession["WEBSITE"];
                if (0 != string.Compare(xiSession["VDNAME"], "/", true))
                {
                    applicationPath = "/" + xiSession["VDNAME"];

                    app = site.Applications[applicationPath];
                    site.Applications.Remove(app);
                }
                mgr.CommitChanges();
                return ActionResult.Success;
            }
            catch(Exception)
            {
                //ensure that uninstallation is clean not matter what
                return ActionResult.Success;
            }
        }
        public static void Main(string[] argc)
        {

        }
    }
}
